/*
 * Experimenter.java
 *
 * Created on den 28 januari 2008, 18:44
 */
package grex.Graphics;

import grex.Conformal.ConformalCalculator;
import grex.ErrorManagement.ErrorManager;
import grex.ErrorManagement.EvolutionListener;
import grex.*;
import grex.Data.ArffTableModel;
import grex.Data.ExtractionArffTableModel;
import grex.Graphics.GREXGUI;
import grex.Nodes.GeneException;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.beans.PropertyVetoException;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.UIManager;

/**
 *
 * @author RIK
 */
public class ExperimenterTab extends javax.swing.JPanel implements EvolutionListener {

    DefaultListModel experiments = new DefaultListModel();
    private int nextExperiment = 0;
    private GREXGUI parent;
    private ArrayList<ArffTableModel> models = new ArrayList<ArffTableModel>();
    private String fileName;
    jifExperimentSummary summary = new jifExperimentSummary();
    ConformalCalculator cc;
    String options;

    /**
     * Creates new form Experimenter
     */
    public ExperimenterTab(GREXGUI parent) {
        setLookAndFeel();
        initComponents();
        this.parent = parent;
        jlstExperiments.setModel(experiments);
        experiments.ensureCapacity(100);
        jLabel1.setVisible(false);
        jftfnrOfParalellExperiments.setVisible(false);
    }

    private void setLookAndFeel() {
        try {
            // Set cross-platform Java L&F (also called "Metal")
            UIManager.setLookAndFeel(
                    UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            // handle exception
        }
    }

    public void addExperiment(Options ops, ArffTableModel af) {
        experiments.addElement(ops);
        models.add(af);
    }

    private void startExperiment() {

        Options ops = (Options) experiments.getElementAt(nextExperiment);
        parent.startNewGREX(ops, this, models.get(nextExperiment), true);
        int[] indexes = new int[nextExperiment + 1];
        for (int i = 0; i < indexes.length; i++) {
            indexes[i] = i;
        }
        jlstExperiments.setSelectedIndices(indexes);
        nextExperiment++;
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {
        setLayout(new BorderLayout());
        
        //JPanel jpnlBase = new JPanel();
        //jpnlBase.setLayout(new BorderLayout());
        JPanel jpnlButtons = new JPanel();
        FlowLayout l = new FlowLayout();
        l.setAlignment(FlowLayout.CENTER);
        jpnlButtons.setLayout(l);
        
        jScrollPane1 = new javax.swing.JScrollPane();
        jlstExperiments = new javax.swing.JList();
        jbtnStart = new javax.swing.JButton();
        jbtnRemove = new javax.swing.JButton();
        jbtnRemoveAll = new JButton("Del All");
        
        add(jScrollPane1,BorderLayout.CENTER);
        add(jpnlButtons,BorderLayout.NORTH);

               
        
        jftfnrOfParalellExperiments = new javax.swing.JFormattedTextField();
        jLabel1 = new javax.swing.JLabel();

        
        jbtnAddExp = new JButton("Add");
        jbtnAddExp.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                parent.addExperiment();
            }
        });   
        
        jbtnAddTimeExpFromFodler = new JButton("Add TSFolder");
        jbtnAddTimeExpFromFodler.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                parent.addTimeSeriesExperimentFromFolder();
            }
        }); 
        
    jbtnAddExpFromFodler = new JButton("Add folder");
        jbtnAddExpFromFodler.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                parent.loadExperimentsFromFolder();
            }
        });        
        
        jScrollPane1.setViewportView(jlstExperiments);

        jbtnStart.setText("Start");
        jbtnStart.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtnStartActionPerformed(evt);
            }
        });

        jbtnRemove.setText("Del");
        jbtnRemove.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jbtnRemoveActionPerformed(evt);
            }
        });

        jbtnRemoveAll.addActionListener(new java.awt.event.ActionListener() {

            public void actionPerformed(java.awt.event.ActionEvent evt) {
                experiments.clear();
                models.clear();
            }
        });

        jftfnrOfParalellExperiments.setText("jFormattedTextField1");
        jftfnrOfParalellExperiments.setValue(new Integer(1));

        jLabel1.setText("Number of parallel experiments:");
        
        jpnlButtons.add(jbtnRemoveAll);
        jpnlButtons.add(jbtnRemove);
        jpnlButtons.add(jbtnAddTimeExpFromFodler);
        jpnlButtons.add(jbtnAddExpFromFodler);
        jpnlButtons.add(jbtnAddExp);
        jpnlButtons.add(jbtnStart);
/*
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(layout.createSequentialGroup().addContainerGap().addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE).addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup().addComponent(jbtnRemoveAll).addComponent(jbtnRemove).addComponent(jbtnAddTimeExpFromFodler).addComponent(jbtnAddExpFromFodler).addComponent(jbtnAddExp)
                .addComponent(jbtnStart)).addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup().addComponent(jLabel1).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(jftfnrOfParalellExperiments, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE))).addContainerGap()));
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(layout.createSequentialGroup().addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(jftfnrOfParalellExperiments, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE).addComponent(jLabel1)).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 227, javax.swing.GroupLayout.PREFERRED_SIZE).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(jbtnStart).addComponent(jbtnAddTimeExpFromFodler).addComponent(jbtnAddExpFromFodler).addComponent(jbtnAddExp).addComponent(jbtnRemove).addComponent(jbtnRemoveAll)).addContainerGap(16, Short.MAX_VALUE)));
*/

    }// </editor-fold>                        

    private void jbtnRemoveActionPerformed(java.awt.event.ActionEvent evt) {
        models.remove(jlstExperiments.getSelectedIndex());
        experiments.remove(jlstExperiments.getSelectedIndex());
    }

    private void jbtnStartActionPerformed(java.awt.event.ActionEvent evt) {
        Options o = (Options) experiments.get(0);
        String file = o.getBNF_FILE();
        String representation = file.substring(0, file.length()-4);
        String fitnessfunction = o.getFITNESS_FUNCTION();
        String pop=""+o.getPOPULATION_SIZE();
        String gen=""+o.getGENERATIONS();
        String pp ="" +o.getPUNISHMENT_FOR_LENGTH();
        String batch = "" +o.getBATCH_SIZE();
        String creation = "" + o.getCREATION_TYPE();
        String depth = ""+ o.getMAX_CREATION_DEPTH();
        String size = ""+o.getMAX_TREE_SIZE();
        String tournament = "" +o.getNR_OF_TOURNAMNET_MEMBERS();
        String laplace = ""+o.isLAPLACE();
        String crossover =""+ o.getCROSSOVER_PROBABILITY();
        String mutation =""+ o.getMUTATION_PROBABILITY();
        String persistence = "" + o.getSTOP_WITHOUT_IMPROVMENT();
        String extraction = "" + (o.getPROBLEM_TYPE()==Options.CLASSIFICATION && o.isRULE_EXTRACT_FROM_RF() || o.getPROBLEM_TYPE() == Options.REGRESSION && o.isRULE_EXTRACTION_FROM_M5PBag());
        for(int i = 1; i< experiments.size();i++){
            Options exp = (Options) experiments.get(i);
            if(!exp.getBNF_FILE().equals(file)){
                representation ="X";
            }
            if(!fitnessfunction.equals(exp.getFITNESS_FUNCTION())){
                fitnessfunction="X";
            }
            if(o.getPOPULATION_SIZE()!=exp.getPOPULATION_SIZE()){
                pop="X";             
            }
            if(o.getGENERATIONS()!=exp.getGENERATIONS()){
                gen="X";             
            }
            if(o.getPUNISHMENT_FOR_LENGTH()!=exp.getPUNISHMENT_FOR_LENGTH()){
                pp="X";             
            }
            if(o.getBATCH_SIZE()!=exp.getBATCH_SIZE()){
                batch="X";             
            }
            if(o.getCREATION_TYPE()!=exp.getCREATION_TYPE()){
                creation="X";             
            }
            if(o.getMAX_CREATION_DEPTH()!=exp.getMAX_CREATION_DEPTH()){
                depth="X";             
            }
            if(o.getMAX_TREE_SIZE()!=exp.getMAX_TREE_SIZE()){
                size="X";             
            }
            if(o.isLAPLACE()!=exp.isLAPLACE()){
                laplace="X";             
            }
            if(o.getNR_OF_TOURNAMNET_MEMBERS()!=exp.getNR_OF_TOURNAMNET_MEMBERS()){
                tournament="X";             
            }
            if(o.getCROSSOVER_PROBABILITY()!=exp.getCROSSOVER_PROBABILITY()){
                crossover="X";             
            }
            if(o.getMUTATION_PROBABILITY()!=exp.getMUTATION_PROBABILITY()){
                mutation="X";             
            }
            if(o.getSTOP_WITHOUT_IMPROVMENT()!=exp.getSTOP_WITHOUT_IMPROVMENT()){
                persistence="X";             
            }
            if((o.getPROBLEM_TYPE()==Options.CLASSIFICATION && o.isRULE_EXTRACT_FROM_RF() || o.getPROBLEM_TYPE() == Options.REGRESSION && o.isRULE_EXTRACTION_FROM_M5PBag())!=(exp.getPROBLEM_TYPE()==Options.CLASSIFICATION && exp.isRULE_EXTRACT_FROM_RF() || exp.getPROBLEM_TYPE() == Options.REGRESSION && exp.isRULE_EXTRACTION_FROM_M5PBag())){
                extraction="X";
            }
            
        }
        fileName = "Exp-" +representation+ "-" + fitnessfunction +"-gen"+gen+"-pop"+
                pop+"-crs"+ crossover +"-mut"+mutation+"-bat" + batch+"-per"+persistence+"-max" + size+
                "-crd"+depth+"-crt"+creation+"-pap"+pp+"-lpc"+laplace.toUpperCase()+"-ext"+extraction.toUpperCase()+"-ID-"+ System.currentTimeMillis() + ".grex";
        summary = new jifExperimentSummary();
        parent.addInternalFrame(summary);
        try {
            summary.setMaximum(true);
        } catch (PropertyVetoException ex) {
            ErrorManager.getInstance().reportError(ex);
        }

        summary.addExepriments(this);

        nextExperiment = 0;

        int exps = (Integer) jftfnrOfParalellExperiments.getValue();

        for (int i = 0; i < exps; i++) {
            startExperiment();
        }
    }
    /**
     * @param args the command line arguments
     */
    // Variables declaration - do not modify                     
    private javax.swing.JLabel jLabel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JButton jbtnRemove;
    private javax.swing.JButton jbtnStart;
    private javax.swing.JButton jbtnRemoveAll;
    private javax.swing.JButton jbtnAddExpFromFodler;
    private javax.swing.JButton jbtnAddTimeExpFromFodler;
    private javax.swing.JButton jbtnAddExp;
    private javax.swing.JFormattedTextField jftfnrOfParalellExperiments;
    private javax.swing.JList jlstExperiments;
    // End of variables declaration                   

    public void evolutionStarted(EvolutionProcess source) {
    }

    public void generationTerminated(EvolutionProcess source) {
    }

    public void batchTerminated(EvolutionProcess source) {
    }

    public void evolutionTerminated(EvolutionProcess source) {
        // writeResultsToFile(preds);
        //     writeResultsToFile(options);
    }
    private String headers = null;
    String preds = "";
    Lock lock = new ReentrantLock();

    @Override
    public synchronized void evolutionProcessTerminated(EvolutionProcess source) {
   //     try {
            lock.lock();
            
             if(headers==null){ 
                 headers = source.getBatchHeaders();
                 writeResultsToFile("Dataset\tTechnique"+source.getHeaders());
             }
             
            writeResultsToFile(source.getMeanResultsForFile());
            summary.addResult(source.getMeanResults());
            
            Options ops = source.getOptions();
            if (ops.isEXP_VAL_FOLDS()) {
               if (cc == null)                    
                    cc = new ConformalCalculator(source.getEnvironment());
               double [] numbers = {0.95,0.9,0.8};//, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55, 0.5};

                for(double eps : numbers ){
                    if(!(source.getData()instanceof ExtractionArffTableModel))
                        cc.calcResult(source.getPredicitveModels(), ops,eps,source.getEnvironment(),"Normal(A)",true);                  
                    else{
                        cc.calcResult(source.getPredicitveModels(), ops,eps,source.getEnvironment(),"Fidelity(C)",true);                  
                        cc.calcResult(source.getPredicitveModels(), ops,eps,source.getEnvironment(),"Fidelity(C)",false);
                        cc.calcResult(source.getPredicitveModels(), ops,eps,source.getEnvironment(),"RegelX(B)",true);
                        cc.calcResult(source.getPredicitveModels(), ops,eps,source.getEnvironment(),"RegelX(B)",false);
                    }
                }
            }
            
            
            
            lock.unlock();
//            writeSensitivityToFile(source.getBatchSensitivity());
 //           preds += source.getBatchResultPredictions();
            //  writeResultsToFile(preds);
  //      } catch (GeneException ex) {
  //          ErrorManager.getInstance().reportError(ex);
  //      }//*/
        options += "\n" + source.getOptions() + "\n";
        if (nextExperiment < experiments.getSize()) {
            startExperiment();
        } else {            
            if(cc!=null){
                cc.closeFile();
                headers=null;
            }
            cc=null;
            
            //   summary.addResult(source.getBatchHeaders() +"\n");
     /*
             * try {
             * writeSensitivityToFile(source.getBatchSensitivityHeaders()); }
             * catch (GeneException ex) {
             * Logger.getLogger(Experimenter.class.getName()).log(Level.SEVERE,
             * null, ex);
            }
             */
        }

    }

    private synchronized void writeResultsToFile(String result) {
        try {
            // Create file 
            FileWriter fstream = new FileWriter(fileName, true);
            BufferedWriter out = new BufferedWriter(fstream);
            out.write(result);
            //Close the output stream
            out.close();
        } catch (Exception e) {//Catch exception if any
            ErrorManager.getInstance().reportError(e);
        }
    }

    private void writeSensitivityToFile(String sensitivity) {
        try {
            // Create file 
            FileWriter fstream = new FileWriter(fileName + "-Sensitivity", true);
            BufferedWriter out = new BufferedWriter(fstream);
            out.write(sensitivity);
            //Close the output stream
            out.close();
        } catch (Exception e) {//Catch exception if any
            ErrorManager.getInstance().reportError(e);
        }
    }
}
